package com.lagou.edu.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.HyperLogLogOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 定义全局过滤器，会对所有路由生效
 */
@Slf4j
@Component  // 让容器扫描到，等同于注册了
public class BlackListFilter implements GlobalFilter, Ordered {

    // 模拟黑名单（实际可以去数据库或者redis中查询）
    private static List<String> blackList = new ArrayList<>();

    @Resource(name = "redisStringTemplate")
    private RedisTemplate  redisStringTemplate;

    static {
        blackList.add("/user/skip");  // 模拟本机地址
        blackList.add("/user/login");  // 模拟本机地址
        blackList.add("/user/skip");  // 模拟本机地址
        blackList.add("/user/addUser");
        blackList.add("/user/register");
        blackList.add("/user/code");
        blackList.add("/user/welcome");
    }

    /**
     * 过滤器核心方法
     *
     * @param exchange 封装了request和response对象的上下文
     * @param chain    网关过滤器链（包含全局过滤器和单路由过滤器）
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 思路：获取客户端ip，判断是否在黑名单中，在的话就拒绝访问，不在的话就放行
        // 从上下文中取出request和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String path = request.getPath().toString();


        // 从request对象中获取客户端ip
        String clientIp = request.getRemoteAddress().getHostString();
        if (redisStringTemplate.hasKey(clientIp)) {
            Integer count = (Integer) redisStringTemplate.opsForValue().get(clientIp);
            if (count > 20) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED); // 状态码
                String data = "you login too many ";
                DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
                return response.writeWith(Mono.just(wrap));
            }
            redisStringTemplate.opsForValue().set(clientIp, count + 1, 0);
        } else {
            redisStringTemplate.opsForValue().set(clientIp, 0, 60, TimeUnit.SECONDS);
        }

        if (path.equals("/user/addUser")) {
            Object register = redisStringTemplate.opsForValue().get("register_" + clientIp);
            if (register == null) {
                redisStringTemplate.opsForValue().set("register_" + clientIp, 1, 60, TimeUnit.SECONDS);
            } else {
                Integer count = (Integer) register + 1;
                redisStringTemplate.opsForValue().set("register_" + clientIp, count, 0);
                if (count >= 5) {
                    HyperLogLogOperations hyperLogLogOperations = redisStringTemplate.opsForHyperLogLog();
                    response.setStatusCode(HttpStatus.FORBIDDEN); // 状态码
                    String data = "you register too many ";
                    DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
                    return response.writeWith(Mono.just(wrap));
                }
            }

        }
        // log.debug(+ "  ");
        String requestId = request.getId();
        System.out.println("requestId" + requestId + "=====>网关拦截IP:" + clientIp);
        System.out.println(request.getURI());
        if (!redisStringTemplate.hasKey(requestId) && !haveUrl(path)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED); // 状态码
            String data = "please login !";
            DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
            return response.writeWith(Mono.just(wrap));
        }

        // 拿着clientIp去黑名单中查询，存在的话就决绝访问
        if (blackList.contains(clientIp)) {
            // 决绝访问，返回
            response.setStatusCode(HttpStatus.UNAUTHORIZED); // 状态码
            //   log.debug("=====>IP:" + clientIp + " 在黑名单中，将被拒绝访问！");
            String data = "Request be denied!";
            DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
            // return response.writeWith(Mono.just(wrap));
        }


        // 合法请求，放行，执行后续的过滤器
        return chain.filter(exchange);
    }

    private boolean haveUrl(String url) {
        for (String s : blackList) {
            if (s.equals(url)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 返回值表示当前过滤器的顺序(优先级)，数值越小，优先级越高
     *
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
